#include <system.h>
#include "kegscale_mk2.h"
#include "display.h"
#include "io_interface.h"
#include "utils.h"
#include "ports.h"

#include "pic_utils.h"

rom char* version = "0.80";

//#pragma CLOCK_FREQ 12000000
#pragma CLOCK_FREQ 48000000
#ifndef SIMULATOR

//#pragma DATA  _CONFIG1L, 0x38 & _USB_LSCLK_OFF_1L & _CPU_DIV_ClkDiv4_1L
#pragma DATA  _CONFIG1L, 0x38 & _USB_LSCLK_OFF_1L & _CPU_DIV_NoClkDiv_1L
#pragma DATA  _CONFIG1H, _FOSC_ECCLKOUTh_1H & _PLL_EN_ON_1H & _PRI_CLK_EN_ON_1H & _FCMEN_OFF_1H & _IESO_OFF_1H
#pragma DATA  _CONFIG2L, 0x3F & _PWRT_OFF_2L & _BOREN_OFF_2L & _BORV_30_2L & _VREGEN_ON_2L
#pragma DATA  _CONFIG2H, 0x1F & _WDTEN_OFF_2H & _WDTPS_32768_2H
#pragma DATA  0x00300004, 0x00
#pragma DATA  _CONFIG3H, 0x88 & _MCLRE_OFF_3H & _HFOFST_OFF_3H
#pragma DATA  _CONFIG4L, 0xCD & _STVREN_ON_4L & _LVP_OFF_4L & _BBSIZ_ON_4L & _XINST_OFF_4L & _BKBUG_OFF_4L
#pragma DATA  0x00300007, 0x00

#pragma DATA  _CONFIG5L, 0x03 & _CP0_OFF_5L & _CP1_OFF_5L
#pragma DATA  _CONFIG5H, 0xC0 & _CPB_OFF_5H & _CPD_OFF_5H
#pragma DATA  _CONFIG6L, 0x03 & _WRT0_OFF_6L & _WRT1_OFF_6L
#pragma DATA  _CONFIG6H, 0xE0 & _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H
#pragma DATA  _CONFIG7L, 0x03 & _EBTR0_OFF_7L & _EBTR1_OFF_7L
#pragma DATA  _CONFIG7H, 0x40 & _EBTRB_OFF_7H

#else //SIMULATOR

#pragma DATA  _CONFIG1H, _INTIO2_OSC_1H
#pragma DATA  _CONFIG2L, _PWRT_ON_2L & _BOR_ON_2L & _BORV_27_2L
#pragma DATA  _CONFIG2H, _WDT_ON_2H & _WDTPS_32_2H // 128 msec Watch-dog
#pragma DATA  _CONFIG3H, _MCLRE_OFF_3H
#pragma DATA  _CONFIG4L, _DEBUG_OFF_4L & _LVP_OFF_4L & _STVR_ON_4L

#pragma DATA  _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L
#pragma DATA  _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
#pragma DATA  _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L
#pragma DATA  _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H
#pragma DATA  _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L
#pragma DATA  _CONFIG7H, _EBTRB_OFF_7H

#endif //SIMULATOR

void set_keg_full_menu();

uint8_t last_ccp_8;
uint8_t last_ccp_16;
uint8_t last_ccp_24;
uint8_t tmr1_24;
uint8_t current_ccp_24;
uint8_t cur_keg;
uint8_t tmr3_24;

volatile bit start_ccp_trigger;
volatile bit display_trigger;
volatile bit button_trigger;
volatile bit button_state;
volatile bit debounced_button;
volatile bit long_button_trigger;

#define LONGPRESS_COUNT 120 //~2.6seconds

void interrupt() {
    if(test_bit(pir1, CCP1IF)) {
        clear_bit(pir1, CCP1IF);
        /* We need to check the Timer1 interrupt flag here
           If TMR1IF is set AND the capture value has its MSB clear
           Then we should store an incremented tmr1_24 value
        */
        if(start_ccp_trigger) {
            // if this is the 1st reading, initialize value
            last_ccp_8 = ccpr1l;
            last_ccp_16 = ccpr1h;
            if(test_bit(pir1, TMR1IF) && ! test_bit(ccpr1h,7)) {
                last_ccp_24 = tmr1_24 + 1;
            } else {
                last_ccp_24 = tmr1_24;
            }
            start_ccp_trigger = 0;
        } else {
            // turn off CCP, since we have a good value
            if(test_bit(pir1, TMR1IF) && ! test_bit(ccpr1h,7)) {
                current_ccp_24 = tmr1_24 + 1;
            } else {
                current_ccp_24 = tmr1_24;
            }
            ccp1con = 0;
        }
    }
    if(test_bit(pir1, TMR1IF)) {
        clear_bit(pir1, TMR1IF);
        tmr1_24++;
        if (tmr1_24 == 0) {
            // every ~5.5 sec
            display_trigger = 1;
        }
    }
    if(test_button_interrupt()) {
        //Interrupt on change
        //Reset the flag in case it changes between now and reading the value
        reset_button_interrupt();
        button_state = test_bit(BUTTON_PORT, BUTTON);
        tmr0l = 0;
        clear_bit(intcon, TMR0IF);  //Clear Timer0 interrupt flag
        set_bit(t0con, TMR0ON);    //Enable Timer0
        clear_bit(t3con, TMR3ON);   //Stop Timer3
        clear_bit(pir2, TMR3IF);  //Clear Timer0 interrupt flag
    }
    if (test_bit(intcon, TMR0IF)) {
        clear_bit(intcon, TMR0IF);
        if (debounced_button == 0 && button_state == 1 && tmr3_24 != LONGPRESS_COUNT) {
            button_trigger = 1;
        }
        if (button_state == 0) {
            tmr3h = 0;
            tmr3l = 0;
            tmr3_24 = 0;
            set_bit(t3con, TMR3ON);
        }
        debounced_button = button_state;
        clear_bit(t0con, TMR0ON);
    }
    if (test_bit(pir2, TMR3IF)) {
        tmr3_24++;
        if(tmr3_24 == LONGPRESS_COUNT) {
            clear_bit(t3con, TMR3ON);
            if (debounced_button == 0 && tmr3_24 == LONGPRESS_COUNT) {
                long_button_trigger = 1;
            }
        }
        clear_bit(pir2, TMR3IF);
    }
    handle_io_interrupts();
}
void reset_display_timer() {
    display_trigger = 0;
}
    
void initialize() {
    kill_interrupts();	// turn off interrupts just in case
    osccon  = 0x7C;
    clear_wdt();
    turn_analog_inputs_off();

    trisa = 0x00;  //All pins configured for output
    porta = 0x00;

    trisb = 0x00;  //All pins configured for output
    portb = 0x00;

#ifdef TRISC
    trisc = 0x00;  //All pins configured for output except CCP1/RC5
    portc = 0x00;
#endif
    set_bit(BUTTON_TRIS, BUTTON);  //Set Button pin as input

    set_bit(CCP_TRIS, CCP1); //Enable CCP as input

    enable_button_interrupt();
    t0con = 0x47;               //Timer0 is disabled as 8-bit with 256:1 prescalar (20msec overflow)
    clear_bit(intcon, TMR0IE);
    clear_bit(intcon, TMR0IF);
    t3con = 0x80;               //Timer3 is disabled
    clear_bit(pie2, TMR3IF);
    set_bit(pie2, TMR3IE);      //Enable Timer3 interrupt

    ccp1con = 0x0; //Reset CCP
    clear_bit(pir1, CCP1IF);	//Clear CCP interrupt flag
    clear_bit(t3con, T3CCP1);	//Start CCP on Timer1
    set_bit(pie1, CCP1IE);      //Enable CCP interrupt
    set_bit(pie1, TMR1IE);      //Enable Timer1 interrupt
    t1con = 0x01;               //Timer1 is enabled with no prescalar

    // LCD init procedure call
    initialize_lcd();

    start_ccp_trigger = 0;
    display_trigger = 0;
    button_trigger = 0;
    long_button_trigger = 0;

    current_ccp_24 = 0;
    cur_keg = 0;

    initialize_io();
    turn_peripheral_ints_on();
    turn_global_ints_on();
}

// Handle any command line tasks we need to do
// Very handy to print out variables, do commands,
// print out some debug, etc...

// Main program entry
main()
{
    uint8_t page_num = 0;
    //Init ports
    initialize();

// Send welcome message to LCD
    //lprintf(kegname);
    show_version();
    while(1) {
	clear_wdt();
        if (0 == ccp1con) {
            // New value read
            update_values();
            start_next_freq_capture();
        }
        handle_io();
        if (display_trigger) {
            update_display(page_num++);
            if(page_num == get_num_pages()) {
                page_num = 0;
            }
            reset_display_timer();
        }
        if (long_button_trigger) {
            long_button_trigger = 0;
            set_keg_full_menu();
        }
        if (button_trigger) {
            button_trigger = 0;
        }
    }
}

